package com.three.netty.core.router;

import com.google.common.eventbus.Subscribe;
import com.three.api.connection.Connection;
import com.three.api.connection.SessionContext;
import com.three.api.event.ConnectionCloseEvent;
import com.three.api.event.PlayerOfflineEvent;
import com.three.api.router.RouterManager;
import com.three.event.EventBus;
import com.three.event.EventConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by mathua on 2017/5/25.
 */
public final class LocalRouterManager extends EventConsumer implements RouterManager<LocalRouter> {
    private static final Logger LOGGER = LoggerFactory.getLogger(LocalRouterManager.class);
    private static final Map<Integer, LocalRouter> EMPTY = new HashMap<>(0);

    /**
     * 本地路由表
     */
    private final Map<Long, Map<Integer, LocalRouter>> routers = new ConcurrentHashMap<>();

    @Override
    public LocalRouter register(long playerId, LocalRouter router) {
        LOGGER.info("register local router success playerId={}, router={}", playerId, router);
        return routers.computeIfAbsent(playerId, s -> new HashMap<>(1)).put(router.getClientType(), router);
    }

    @Override
    public boolean unRegister(long playerId, int clientType) {
        LocalRouter router = routers.getOrDefault(playerId, EMPTY).remove(clientType);
        LOGGER.info("unRegister local router success playerId={}, router={}", playerId, router);
        return true;
    }

    @Override
    public Set<LocalRouter> lookupAll(long playerId) {
        return new HashSet<>(routers.getOrDefault(playerId, EMPTY).values());
    }

    @Override
    public LocalRouter lookup(long playerId, int clientType) {
        LocalRouter router = routers.getOrDefault(playerId, EMPTY).get(clientType);
        LOGGER.info("lookup local router playerId={}, router={}", playerId, router);
        return router;
    }

    public Map<Long, Map<Integer, LocalRouter>> routers() {
        return routers;
    }

    /**
     * 监听链接关闭事件，清理失效的路由
     *
     * @param event
     */
    @Subscribe
    void on(ConnectionCloseEvent event) {
        Connection connection = event.connection;
        if (connection == null) return;
        SessionContext context = connection.getSessionContext();

        long playerId = context.getPlayerId();
        if (playerId == 0) return;

        EventBus.I.post(new PlayerOfflineEvent(event.connection, playerId));
        int clientType = context.getClientType();
        LocalRouter localRouter = routers.getOrDefault(playerId, EMPTY).get(clientType);
        if (localRouter == null) return;

        String connId = connection.getId();
        //2.检测下，是否是同一个链接, 如果客户端重连，老的路由会被新的链接覆盖
        if (connId.equals(localRouter.getRouteValue().getId())) {
            //3.删除路由
            routers.getOrDefault(playerId, EMPTY).remove(clientType);
            LOGGER.info("clean disconnected local route, playerId={}, route={}", playerId, localRouter);
        } else { //如果不相等，则log一下
            LOGGER.info("clean disconnected local route, not clean:playerId={}, route={}", playerId, localRouter);
        }
    }
}
